package com.nescafe.nescafepromo.command.user;

import java.util.ArrayList;
import java.util.List;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.datastore.Query.SortDirection;
import com.google.appengine.api.datastore.Transaction;
import com.nescafe.nescafepromo.command.Command;
import com.nescafe.nescafepromo.command.CommandException;
import com.nescafe.nescafepromo.entity.EntityType;
import com.nescafe.nescafepromo.entity.Participant;
import com.nescafe.nescafepromo.entity.TotalPoints;
import com.nescafe.nescafepromo.model.MainPageInfo;
import com.nescafe.nescafepromo.model.NPRequest;
import com.nescafe.nescafepromo.model.NPResponse;

public class GetMainPageInfo implements Command {

	@Override
	public NPResponse execute(NPRequest req) throws CommandException {
		NPResponse res = null;
		try {

			MainPageInfo mpi = new MainPageInfo();
			DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
			if (req.getParams().containsKey("email")) {
				String email = req.getParam("email");
				ArrayList<Entity> toBeInserted = null;
				Key participantKey = EntityType.PARTICIPANT.getKey(email);
				Key totalPointsKey = EntityType.TOTAL_POINTS.getKey(participantKey, email);

				Participant participant = null;
				TotalPoints totalPoints = null;

				try {
					participant = new Participant(ds.get(participantKey));
					totalPoints = new TotalPoints(ds.get(totalPointsKey));

					if (participant.getFacebookID() == null) {
						toBeInserted = new ArrayList<Entity>();
						participant.setFacebookID(req.getParam("fb_id"));
						participant.setName(req.getParam("name"));
						participant.setLocation(req.getParam("location"));
						toBeInserted.add(participant.toEntity());
					}

				} catch (EntityNotFoundException notfoundE) {
					toBeInserted = new ArrayList<Entity>();
					participant = new Participant(email);
					participant.setFacebookID(req.getParam("fb_id"));
					participant.setName(req.getParam("name"));
					participant.setLocation(req.getParam("location"));
					toBeInserted.add(participant.toEntity());
					totalPoints = new TotalPoints(participantKey);
					toBeInserted.add(totalPoints.toEntity());
				}
				if (toBeInserted != null && toBeInserted.size() > 0) {
					Transaction txn = null;
					try {
						txn = ds.beginTransaction();
						ds.put(toBeInserted);
						txn.commit();
					} finally {
						if (txn != null && txn.isActive()) {
							txn.rollback();
						}
					}
				}

				mpi.setPoints(totalPoints.getTotalPonts());
			}

			// Get Top 10 participants
			Query q = new Query(EntityType.TOTAL_POINTS.getKind());
			q.addSort(TotalPoints.TOTAL_POINTS_FIELD, SortDirection.DESCENDING);
			PreparedQuery pq = ds.prepare(q);
			List<Entity> top10Points = pq.asList(FetchOptions.Builder.withLimit(10));

			String participantEntityKind = EntityType.PARTICIPANT.getKind();
			q = new Query(participantEntityKind);
			List<Key> participantKeys = new ArrayList<Key>();
			for (Entity tpEntity : top10Points) {
				String tpEmail = tpEntity.getKey().getName();
				Key pKey = EntityType.PARTICIPANT.getKey(tpEmail);
				participantKeys.add(pKey);
			}
			q.addFilter(Entity.KEY_RESERVED_PROPERTY, FilterOperator.IN, participantKeys);
			pq = ds.prepare(q);
			List<Entity> top10Participants = pq.asList(FetchOptions.Builder.withLimit(10));
			mpi.setTop10Participants(top10Participants);
			mpi.setTop10Points(top10Points);
			res = new NPResponse(mpi);
		} catch (Exception e) {
			throw new CommandException(e.getMessage());
		}

		return res;
	}

}
